package com.copro.chemdb.result;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.ihelpuoo.db.sql.SQLSegment;
import org.ihelpuoo.lang.StringUtils;
import org.ihelpuoo.parser.segment.CharSegment;
import org.ihelpuoo.parser.segment.Segment;

import com.copro.chemdb.constants.ConstValue;
import com.copro.chemdb.constants.ConstValueUtils;
import com.copro.chemdb.result.ResultUtils.AnswerDetailGetter;
import com.copro.chemdb.subject.Subject;
import com.copro.chemdb.subject.SubjectUtils;
import com.copro.chemdb.subject.opt.Option;
import com.copro.simple.Application;
import com.copro.simple.SimpleException;

public class SegmentWriter {

	private String prefix;

	public SegmentWriter(String prefix) {
		this.prefix = prefix;
	}

	public List<String> renderSubjects(Application app, int questionId,
			Result result) throws SimpleException {
		List<String> strSubjects = new ArrayList<String>();
		// get root subjects
		List<Subject> subjects = null;
		subjects = getRootSubjects(app, questionId, result);
		Iterator<Subject> it = subjects.iterator();
		while (it.hasNext()) {
			Subject sb = it.next();
			strSubjects.add(renderSubject(app, sb, result));
		}
		return strSubjects;
	}

	private List<Subject> getRootSubjects(Application app, int questionId,
			Result result) throws SimpleException {
		List<Subject> subjects;
		if (result.isFromDB()) {
			subjects = SubjectUtils.queryRootDBSubjects(app, questionId);
		} else {
			subjects = SubjectUtils.queryRootQuesSubjects(app, questionId);
		}
		return subjects;
	}

	private String renderSubject(Application app, Subject subject, Result result)
			throws SimpleException {
		String strRender = null;
		switch (subject.getType()) {
		case Subject.DEFAULT:
			strRender = renderCombinedSubject(app, subject, result);
			break;
		case Subject.TEXT:
			strRender = renderFilledSubject(app, subject, result);
			break;
		case Subject.SINGLE_SELECT:
		case Subject.MULTI_SELECT:
			strRender = renderCheckOrRadioSubject(app, subject, result);
			break;
		case Subject.ENUM:
			strRender = renderEnumSubject(app, subject, result);
			break;
		default:
			throw new SimpleException("Unsupport subject type "
					+ subject.getType());
		}
		return strRender;
	}

	private String renderEnumSubject(Application app, Subject subject,
			Result result) throws SimpleException {
		Segment segRender = null;
		segRender = getSegment(app, subject);
		fillSegmentWithSubject(subject, segRender, result.isFromQues());
		// try to get the subject options
		List<ConstValue> options = ConstValueUtils.getConstValueList(app,
				subject.getEnumType());
		for (int i = 0; i < options.size(); i++) {
			segRender.add("options", renderOption(app, result.getId(), subject
					.getId(), options.get(i)));
		}
		return segRender.toString();
	}

	private Object renderOption(Application app, int resultId, int subjectId,
			ConstValue constValue) throws SimpleException {
		Segment segRender = app.getCharSegmentFactory().create(
				prefix + ".option");
		segRender.set("id", constValue.getId());
		segRender.set("name", constValue.getName());
		// try to get the subject answer
		Answer answer = getAnswer(app, resultId, subjectId, constValue.getId());
		if (null != answer) {
			segRender.set("selected", "selected");
		}
		return segRender.toString();
	}

	private String renderCheckOrRadioSubject(Application app, Subject subject,
			Result result) throws SimpleException {
		Segment segRender = null;
		segRender = getSegment(app, subject);
		fillSegmentWithSubject(subject, segRender, result.isFromQues());
		// try to get the subject options
		List<Option> options = SubjectUtils.queryOptions(app, subject);
		for (int i = 0; i < options.size(); i++) {
			segRender.add("options", renderCheckOrRadio(app, result,
					subject, options.get(i)));
		}
		return segRender.toString();
	}

	private Segment getSegment(Application app, Subject subject) {
		Segment segRender;
		String pattern = subject.getPattern();
		if (StringUtils.isBlank(pattern)) {
			segRender = app.getCharSegmentFactory().create(
					prefix + ".type_" + subject.getType());
		} else {
			if (pattern.indexOf(":") == 0) {
				segRender = app.getCharSegmentFactory().create(
						prefix + "." + pattern.substring(1));
			} else {
				segRender = new CharSegment(subject.getPattern());
			}
		}
		return segRender;
	}

	private Object renderCheckOrRadio(Application app, Result result,
			Subject subject, Option option) throws SimpleException {
		String template = null;
		if (subject.getType() == 2) {
			template = option.isIsext() ? "radioExt" : "radio";
		} else {
			template = option.isIsext() ? "checkboxExt" : "checkbox";
		}
		Segment segRender = app.getCharSegmentFactory().create(
				prefix + "." + template);
		segRender.set("isExt", option.isIsext());
		segRender.set("id", option.getId());
		segRender.set("subjectId", subject.getId());
		segRender.set("text", result.isFromQues() ? option.getText() : option
				.getDBText());
		// try to get the subject answer
		Answer answer = getAnswer(app, result.getId(), subject.getId(), option
				.getId());
		if (null != answer) {
			segRender.set("checked", "CHECKED");
			segRender.set("value", answer.getStrValue());
		}
		return segRender.toString();
	}

	private Answer getAnswer(Application app, int resultId, int subjectId,
			int optionId) throws SimpleException {
		AnswerDetailGetter callback = new AnswerDetailGetter(null);
		SQLSegment sql = app.getSQL("getResultOptionAnswers");
		sql.set("id_T_subject", subjectId <= 0 ? "NULL" : subjectId);
		sql.set("resultId", resultId <= 0 ? "NULL" : resultId);
		// TODO change the t_option id to PK, min as 1 !
		sql.set("optionId", optionId < 0 ? "NULL" : optionId);
		app.query(sql.toString(), callback);
		return callback.getObject();
	}

	private String renderFilledSubject(Application app, Subject subject,
			Result result) throws SimpleException {
		Segment segRender = null;
		segRender = getSegment(app, subject);
		fillSegmentWithSubject(subject, segRender, result.isFromQues());
		// try to get the subject answer
		List<Answer> answers = null;
		if (result.getId() > 0) {
			answers = ResultUtils.getAnswerList(app, result.getId(), subject
					.getId());
		}
		if (null != answers && answers.size() > 0) {
			segRender.set("value", answers.get(0).getStrValue());
		}
		// get children subjects
		List<Subject> subjects = null;
		subjects = getChildSubjects(app, subject, result);
		for (int i = 0; i < subjects.size(); i++) {
			segRender.add("children", renderSubject(app, subjects.get(i),
					result));
		}
		return segRender.toString();
	}

	private void fillSegmentWithSubject(Subject subject, Segment segRender,
			boolean isShowTitle) {
		segRender.set("code", subject.getCode());
		segRender.set("title", isShowTitle ? subject.getTitle() : subject
				.getName());
		segRender.set("id", subject.getId());
		segRender.set("type", subject.getType());
		segRender.set("parentId", subject.getParentId());
	}

	private String renderCombinedSubject(Application app, Subject subject,
			Result result) throws SimpleException {
		Segment segRender = null;
		segRender = getSegment(app, subject);
		// get children subjects
		List<Subject> subjects = null;
		subjects = getChildSubjects(app, subject, result);

		for (int i = 0; i < subjects.size(); i++) {
			segRender.add("children", renderSubject(app, subjects.get(i),
					result));
		}
		segRender.set("code", subject.getCode());
		segRender.set("title", result.isFromQues() ? subject.getTitle()
				: subject.getName());
		return segRender.toString();
	}

	private List<Subject> getChildSubjects(Application app, Subject subject,
			Result result) throws SimpleException {
		List<Subject> subjects;
		if (result.isFromDB()) {
			subjects = SubjectUtils.queryChildrenDBSubjects(app, subject);
		} else {
			subjects = SubjectUtils.queryChildrenQuesSubjects(app, subject);
		}
		return subjects;
	}

	public String getPrefix() {
		return prefix;
	}

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

}
